﻿
using System;
using System.Collections.Generic;
using System.Linq;
#if NET8_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
#endif

namespace DimensionsHelper.Common.Metadata.Script;

/// <summary>
///     检索表达式中标识符定义的数据接口。
/// </summary>
public abstract class MetadataProvider
{
    /// <summary>
    ///     默认的空接口。
    /// </summary>
    public static readonly MetadataProvider Empty = new EmptyMetadataProvider();

    /// <summary>
    ///     查找指定名称字段的分类字段定义，列表需要按照定义顺序排列。
    /// </summary>
    /// <param name="fieldName">给定字段名</param>
    /// <returns></returns>
    public abstract IList<string> FetchCategoriesDefinition(string fieldName);

    /// <summary>
    ///     查找指定字段名的值。
    /// </summary>
    /// <param name="fieldName"></param>
    /// <returns></returns>
    public abstract string FetchFieldValue(string fieldName);
}


public class EmptyMetadataProvider : MetadataProvider
{
    public override IList<string> FetchCategoriesDefinition(string fieldName)
    {
        return new List<string>();
    }

    public override string FetchFieldValue(string fieldName)
    {
        return string.Empty;
    }
}


/// <summary>
///     元数据表达式类型。
/// </summary>
public enum ExpressionKinds
{
    /// <summary>
    ///     空表达式
    /// </summary>
    Empty,

    /// <summary>
    ///     一元表达式。
    /// </summary>
    Unary,

    /// <summary>
    ///     二元表达式。
    /// </summary>
    Binary,

    /// <summary>
    ///     成员调用表达式。
    /// </summary>
    Member,

    /// <summary>
    ///     索引表达式。
    /// </summary>
    Index,

    /// <summary>
    ///     函数调用表达式。
    /// </summary>
    Call,

    /// <summary>
    ///     常量表达式。
    /// </summary>
    Literal,

    /// <summary>
    ///     标识符表达式。
    /// </summary>
    Identifier
}


/// <summary>
///     元数据表达式的基础类型，所有表达式对象都继承此类。
/// </summary>
public abstract class Expression : Token
{

    private string? _metadataContext;

    /// <summary>
    ///     元数据表达式的基础类型，所有表达式对象都继承此类。
    /// </summary>
    protected Expression(ExpressionKinds kind, int start) : base(TokenKinds.Expression, start)
    {
        ExpressionKind = kind;
    }

    /// <summary>
    ///     表达式类型。
    /// </summary>
    public ExpressionKinds ExpressionKind { get; }

    /// <summary>
    ///     父级表达式。
    /// </summary>
    public Expression? Parent { get; internal set; }

    /// <summary>
    ///     当前表达式是否被括号包裹。
    /// </summary>
    public bool WithParentheses { get; internal set; }

    /// <summary>
    ///     当前的数据上下文变量名。
    /// </summary>
    public string MetadataContext
    {
        get
        {
            if (!string.IsNullOrEmpty(_metadataContext))
            {
                return _metadataContext!;
            }

            Expression? p = Parent;
            while (p != null)
            {
                if (!string.IsNullOrEmpty(p._metadataContext))
                {
                    return _metadataContext = p._metadataContext!;
                }

                p = p.Parent;
            }

            return _metadataContext!;
        }

        set => _metadataContext = value;
    }

    /// <summary>
    ///     元数据检索对象。
    /// </summary>
    public static MetadataProvider MetadataProvider { get; set; } = MetadataProvider.Empty;

    /// <summary>
    ///     计算当前表达式的返回类型。
    /// </summary>
    public abstract ExpressionBasicType Evaluate();

    /// <summary>
    ///     重置元数据检索对象。
    /// </summary>
    public static void ResetMetadataProvider()
    {
        MetadataProvider = MetadataProvider.Empty;
    }


    protected void SetProperty<T>(ref T? field, T? value) where T : Expression
    {
        if (field != null)
        {
            field.Parent = null;
        }

        field = value;

        if (value != null)
        {
            value.Parent = this;
        }
    }
}

/// <summary>
///     空表达式。
/// </summary>
public class EmptyExpression : Expression
{
    /// <summary>
    ///     空表达式。
    /// </summary>
    public EmptyExpression(int start) : base(ExpressionKinds.Empty, start)
    {
    }

    public override ExpressionBasicType Evaluate()
    {
        return new ExpressionNull();
    }
}


/// <summary>
///     表达式中的一元操作符表达式，只有Not一个一元操作符。
/// </summary>
public class UnaryExpression : Expression
{
        
    private Expression? _expression;

    /// <summary>
    ///     表达式中的一元操作符表达式，只有Not一个一元操作符。
    /// </summary>
    public UnaryExpression(int start) : base(ExpressionKinds.Unary, start)
    {
    }

    public TokenKinds OperatorKind => TokenKinds.Not;

    /// <summary>
    ///     一元表达式的右值。
    /// </summary>
    public Expression? Expression
    {
        get => _expression;
        internal set => SetProperty(ref _expression, value);
    }

    public override ExpressionBasicType Evaluate()
    {
        if (Expression == null)
        {
            throw new Exception($"表达式'{Text}'无效。");
        }

        // 转换成负数
        if (OperatorKind == TokenKinds.Subtract)
        {
            if (Expression.Kind == TokenKinds.Double)
            {
                return new ExpressionDouble(-((ExpressionDouble)Expression.Evaluate().ConvertTo(BasicTypes.Double))
                    .Value);
            }

            if (Expression.Kind == TokenKinds.Integer)
            {
                return new ExpressionInteger(
                    -((ExpressionInteger)Expression.Evaluate().ConvertTo(BasicTypes.Integer)).Value);
            }
        }

        return new ExpressionBoolean(
            !((ExpressionBoolean)Expression.Evaluate().ConvertTo(BasicTypes.Boolean)).Value);
    }
}


/// <summary>
///     表达式中的二元操作符表达式。
/// </summary>
public class BinaryExpression : Expression
{

    private Expression? _left;
    private Expression? _right;

    public BinaryExpression(TokenKinds operatorKind, int start) : base(ExpressionKinds.Binary, start)
    {
        Operator = operatorKind;

        if (!IsBinaryOperator(operatorKind))
        {
            throw new Exception($"{operatorKind} 不是有效的二元操作符。");
        }
    }

    /// <summary>
    ///     二元表达式的操作符。
    /// </summary>
    public TokenKinds Operator { get; }

    /// <summary>
    ///     二元操作符的左值
    /// </summary>
    public Expression? LeftOperand
    {
        get => _left;
        internal set => SetProperty(ref _left, value);
    }

    /// <summary>
    ///     二元操作符的右值
    /// </summary>
    public Expression? RightOperand
    {
        get => _right;
        internal set => SetProperty(ref _right, value);
    }

    /// <summary>
    ///     判断给定字符是否是二元操作符。
    /// </summary>
    /// <param name="kind"></param>
    /// <returns></returns>
    public static bool IsBinaryOperator(TokenKinds kind)
    {
        return kind is TokenKinds.Add
                or TokenKinds.Subtract
                or TokenKinds.Star
                or TokenKinds.Slash
                or TokenKinds.Mod
                or TokenKinds.Equal
                or TokenKinds.NotEqual
                or TokenKinds.EqualStar
                or TokenKinds.Greater
                or TokenKinds.GreaterEqual
                or TokenKinds.LessEqual
                or TokenKinds.Less
                or TokenKinds.And
                or TokenKinds.Or
                or TokenKinds.Xor
            ;
    }

    /// <summary>
    ///     获取二元操作符的操作符优先级，数字越大，优先级越高，进行二元操作符解析时越是优先结合。
    /// </summary>
    /// <param name="kind"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static int GetBinaryOperatorPriority(TokenKinds kind)
    {
        switch (kind)
        {
            case TokenKinds.And:
            case TokenKinds.Or:
            case TokenKinds.Xor:
                return 1;
            case TokenKinds.Equal:
            case TokenKinds.NotEqual:
            case TokenKinds.EqualStar:
            case TokenKinds.Greater:
            case TokenKinds.GreaterEqual:
            case TokenKinds.Less:
            case TokenKinds.LessEqual:
                return 2;
            case TokenKinds.Add:
            case TokenKinds.Subtract:
                return 3;
            case TokenKinds.Star:
            case TokenKinds.Slash:
            case TokenKinds.Mod:
                return 4;
            default:
                throw new Exception($"{kind}不是二元操作符。");
        }
    }

#if NET8_0_OR_GREATER
    [MemberNotNullWhen(true, nameof(LeftOperand), nameof(RightOperand))]
#endif
    protected override bool IsValid()
    {
        return base.IsValid() && LeftOperand != null && RightOperand != null;
    }

    public override ExpressionBasicType Evaluate()
    {
        if (!IsValid())
        {
            throw new Exception($"'{Text}' 不是有效的二元表达式。");
        }

        ExpressionBasicType left = LeftOperand!.Evaluate();
        ExpressionBasicType right = RightOperand!.Evaluate();

        if (Operator == TokenKinds.EqualStar)
        {
            Categorical leftCat = (Categorical)left.ConvertTo(BasicTypes.Categorical);
            Categorical rightCat = (Categorical)right.ConvertTo(BasicTypes.Categorical);
            return new ExpressionBoolean(leftCat.Intersection(rightCat).Count > 0);
        }

        switch (Operator)
        {
            case TokenKinds.Add:
                return left.Add(right);
            case TokenKinds.Subtract:
                return left.Subtract(right);
            case TokenKinds.Star:
                return left.Multiply(right);
            case TokenKinds.Slash:
                return left.Divide(right);
            case TokenKinds.Mod:
                return left.Modulo(right);
            case TokenKinds.Equal:
                return left.IsEqualTo(right);
            case TokenKinds.NotEqual:
                return new ExpressionBoolean(!((ExpressionBoolean)left.IsEqualTo(right)).Value);
            case TokenKinds.Greater:
                return left.IsGreaterThan(right);
            case TokenKinds.GreaterEqual:
                return left.IsGreaterThanEqual(right);
            case TokenKinds.Less:
                return left.IsLessThan(right);
            case TokenKinds.LessEqual:
                return left.IsLessThanEqual(right);
            case TokenKinds.And:
                return left.And(right);
            case TokenKinds.Or:
                return left.Or(right);
            case TokenKinds.Xor:
                return left.Xor(right);
            default:
                throw new Exception($"{Operator} 不是有效的二元操作符。");
        }
    }
}


/// <summary>
///     索引表达式。
/// </summary>
public class IndexExpression : Expression
{
    /// <summary>
    ///     索引表达式。
    /// </summary>
    public IndexExpression(int start) : base(ExpressionKinds.Index, start)
    {
    }

    /// <summary>
    ///     索引的对象表达式。
    /// </summary>
    public Expression? Object { get; internal set; }

    /// <summary>
    ///     索引表达式。
    /// </summary>
    public Expression? Index { get; internal set; }


    public override ExpressionBasicType Evaluate()
    {
        // 表达式中，单纯的索引表达式不应该查找到有效的值，需要搭配MemberExpression才可以，
        // 类似 obj[{index}].member 这种格式。
        return new ExpressionNull();
    }


#if NET8_0_OR_GREATER
    [MemberNotNullWhen(true, nameof(Object), nameof(Index))]
#endif
    protected override bool IsValid()
    {
        return base.IsValid() && Object != null && Index != null;
    }


#if NET8_0_OR_GREATER
    [MemberNotNull(nameof(Object), nameof(Index))]
#endif
    private void Validate()
    {
        if (!IsValid())
        {
            throw new Exception($"'{Text}' 不是有效的索引表达式。");
        }
    }

    public override string ToString()
    {
        Validate();
        return $"{Object}[{Index}]";
    }
}

/// <summary>
///     成员表达式。
/// </summary>
public class MemberExpression : Expression
{

    private Identifier? _member;
    private Expression? _obj;

    /// <summary>
    ///     成员表达式。
    /// </summary>
    public MemberExpression(int start) : base(ExpressionKinds.Member, start)
    {
    }

    /// <summary>
    ///     表达式对象名。
    /// </summary>
    public Expression? Object
    {
        get => _obj;
        internal set => SetProperty(ref _obj, value);
    }

    /// <summary>
    ///     表达式成员名。
    /// </summary>
    public Identifier? Member
    {
        get => _member;
        internal set => SetProperty(ref _member, value);
    }


#if NET8_0_OR_GREATER
    [MemberNotNullWhen(true, nameof(Object), nameof(Member))]
#endif
    protected override bool IsValid()
    {
        return base.IsValid() && Object != null && Member != null;
    }


#if NET8_0_OR_GREATER
    [MemberNotNull(nameof(Object), nameof(Member))]
#endif
    internal void Validate()
    {
        if (!IsValid())
        {
            throw new Exception($"'{Text}' 不是有效的成员表达式。");
        }
    }

    public override ExpressionBasicType Evaluate()
    {
        return new Categorical(MetadataProvider.FetchFieldValue(ToString()));
    }

    public override string ToString()
    {
        Validate();
        return $"{Object}.{Member}";
    }
}

/// <summary>
///     表达式中的函数调用表达式
/// </summary>
public class CallExpression : Expression
{
    private readonly List<Expression> _arguments = [];
    private Expression? _callee;

    /// <summary>
    ///     表达式中的函数调用表达式
    /// </summary>
    public CallExpression(int start) : base(ExpressionKinds.Call, start)
    {
    }

    /// <summary>
    ///     函数调用表达式。
    /// </summary>
    public Expression? Callee
    {
        get => _callee;
        internal set => SetProperty(ref _callee, value);
    }

    /// <summary>
    ///     表达式的参数列表。
    /// </summary>
    public IReadOnlyList<Expression> Arguments => _arguments;


    /// <summary>
    ///     向当前参数列表末尾追加新的参数。
    /// </summary>
    /// <param name="argument"></param>
    public void PushArgument(Expression argument)
    {
        _arguments.Add(argument);
        argument.Parent = this;
    }


#if NET8_0_OR_GREATER
    [MemberNotNullWhen(true, nameof(Callee))]
#endif
    protected override bool IsValid()
    {
        return base.IsValid() && Callee != null;
    }

#if NET8_0_OR_GREATER
    [MemberNotNull(nameof(Callee))]
#endif
    private void Validate()
    {
        if (!IsValid())
        {
            throw new Exception($"'{Text}' 不是有效的函数调用表达式。");
        }
    }

    private ExpressionBasicType[] GetArguments()
    {
        Validate();

        var args = new List<ExpressionBasicType>();

        // 如果Callee是MemberExpression，将调用对象添加到第一个参数。
        if (Callee!.ExpressionKind == ExpressionKinds.Member)
        {
            var member = (MemberExpression)Callee;
            member.Validate();
            args.Add(member.Object!.Evaluate());
        }

        args.AddRange(_arguments.Select(item => item.Evaluate()));
        return args.ToArray();
    }

    private string GetFunctionName()
    {
        Validate();

        if (Callee!.ExpressionKind != ExpressionKinds.Member)
        {
            return Callee.Text;
        }

        var member = (MemberExpression)Callee;
        member.Validate();
        return member.Member!.Text;
    }


    public override ExpressionBasicType Evaluate()
    {
        return ExpressionBuiltInFunctions.Invoke(GetFunctionName(), GetArguments());
    }
}